﻿using Sasa.QualityTools.CodeAnalysis.Common;
using Sasa.QualityTools.CodeAnalysis.Core.Requests;
using Sasa.QualityTools.CodeAnalysis.Core.Responses;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

namespace Sasa.QualityTools.CodeAnalysis.Core.Services.CodeAnalysis
{
    /// <summary>
    /// This class provides the feature to analyze an assembly with FxCop.
    /// </summary>
    internal abstract class CodeAnalyzerBase
    {
        private CodeAnalysisRequest request;


        protected internal string OutputPath
        {
            get
            {
                if (!File.Exists(request.Target)) throw new InvalidOperationException("The specified code analysis target (" + request.Target + ") doesn't exist.");
                return Path.Combine(Path.GetDirectoryName(request.Target), "CodeAnalysisReport.xml");
            }
        }

        protected internal abstract IFxCopReportValueConverter FxCopReportValueConverter { get; }


        protected CodeAnalyzerBase(CodeAnalysisRequest request)
        {
            if (request == null) throw new ArgumentNullException("request");

            this.request = request;
        }


        public FxCopReport Analyze()
        {
            var process = CreateFxCopCmdProcess();
            try
            {
                process.Start();
                process.WaitForExit();
            }
            catch (Exception e)
            {
                Logger.Error("Failed to analyze code because FxCopCmd process throws the following exception.", e);
                throw new FxCopExecutionException("Failed to analyze code because FxCopCmd process throws the following exception.", e);
            }

            if (process.ExitCode != 0)
            {
                // TODO: change implementation
                Logger.Error("Failed to analyze code because FxCopCmd returned error code {0}.", process.ExitCode);
                throw new FxCopExecutionException(process.ExitCode);
            }

            var report = new FxCopReport();
            report.Converter = FxCopReportValueConverter;
            report.Load(OutputPath);

            return report;
        }

        private Process CreateFxCopCmdProcess()
        {
            if (!File.Exists(request.FxCopCmdPath)) throw new ArgumentException("The specified FxCopCmd path (" + request.FxCopCmdPath + ") doesn't exist.");

            var command = String.Format(@"""{0}""", request.FxCopCmdPath);
            var arguments = String.Join<string>(" ", CreateFxCopCmdOptions());

            var process = new Process();
            process.StartInfo = new ProcessStartInfo(command, arguments);
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.RedirectStandardOutput = false;
            process.StartInfo.RedirectStandardError = false;

            Logger.Info("Created process: {0} {1}", command, arguments);

            return process;
        }

        protected internal abstract IEnumerable<string> CreateFxCopCmdOptions();
    }
}
